User Guide
Pre-Alpha Release
This version of JSxCAD is pre-alpha.
Some things are broken and some things will break.
You have been warned. :)
Main Site
Discussion Forum
Repository
Introduction
The initial app can be opened via:
https://jsxcad.js.org/preAlpha
Appending #project will select a project (stored within local storage):
https://jsxcad.js.org/preAlpha#circle
Appending @gistUrl will load the initial script from a file named 'script' in the provided gist url:
https://jsxcad.js.org/preAlpha#circle@https://api.github.com/gists/3c39d513e91278681eed2eea27b0e589
Replace 3c39d513e91278681eed2eea27b0e589 in the example with your gist id.
Saving the project to gist is not yet supported.
Language
A small compiler is included which will transform input to a canonical form.
The basic api is implicitly imported into the top level scope, making 'circle', etc, available.
If no 'main' export is provided the compiler collects top level expressions other than exports, and bundles them into an implicit main function.
An implicit 'return' is placed before the last expression.
All functions are made async, and all function calls have an implicit await.
The intent is that it should be possible to write simple things easily, and have these translated into es6 modules automatically, while also allowing
es6 modules to be written out explicitly.
In some cases the analysis is confused by missing semicolons. If a script does not work, make sure all statements are terminated with semicolons.
Returning a shape from the script should produce a preview.
In order to generate stl, etc, use an operator like writeStl as described below. This should open a new window with a download button.
Operator Guide
Above
Moves the shape so that it is just above the origin.
assemble(cube(10).above(),
cylinder(2, 15).rotateY(90))
Arc Cosine
Gives the arc cosine converted to degrees.
acos(a) => Math.acos(a) / (Math.PI * 2) * 360;
acos(0) = 90
acos(0.5) = 60
acos(1) = 0
Assemble
Produces an assembly of shapes that can be manipulated as a single shape.
assemble(circle(20).translate([0, 0, -12]),
square(40).translate([0, 0, 16]).outline(),
cylinder(10, 20));
Components of the assembly can be extracted by tag filtering.
Components later in the assembly project holes into components earlier in the assembly so that the geometries are disjoint.
assemble(cube(30).above().as('cube'),
cylinder(10, 40).above().as('cylinder'))
assemble(cube(30).above().as('cube'),
cylinder(10, 40).above().as('cylinder'))
.keep('cube')
assemble(cube(30).above().as('cube'),
assemble(circle(40),
circle(50).outline()).as('circles'))
.keep('circles')
assemble(cube(30).above().as('cube'),
assemble(circle(40).as('circle'),
circle(50).outline().as('outline')))
.drop('outline')
Back
Moves the shape so that it is just behind the origin.
assemble(cylinder(2, 15).translate([0, 0, 2.5]),
cube(10).back())
Below
Moves the shape so that it is just below the origin.
assemble(cylinder(2, 15).rotateY(90),
cube(10).below())
Center
Moves the shape so that it is centered on the origin.
cube({ corner1: [30, -30, 10],
corner2: [10, -10, 0] })
cube({ corner1: [30, -30, 10],
corner2: [10, -10, 0] })
.center()
Chain Hull
Builds a convex hull between adjacent pairs in a sequence of shapes.
chainHull(cube(3).translate([-5, 5]),
sphere(3).translate([5, -5]),
cylinder(3, 10).translate([-10, -10]))
.translate([10, 10])
chainHull(circle(20).translate([0, 0, -10]),
circle(10),
circle(20).translate([0, 0, 10]))
Circle (disc)
Circles are approximated as surfaces delimeted by regular polygons.
Properly speaking what is produced here are discs.
The circle perimeter can be extracted via outline().
circle({ radius: 10,
resolution: 8 })
circle({ diameter: 20,
resolution: 16 })
Cosine
Gives the cosine in degrees.
cos(a) => Math.cos(a / 360 * Math.PI * 2);
cos(0) = 1
cos(45) = 0.707
cos(90) = 0
CrossSection
Produces a cross-section of a solid as a surface.
difference(cylinder(10, 10),
cylinder(8, 10))
difference(sphere(10),
sphere(8))
.crossSection()
difference(sphere(10),
sphere(8))
.crossSection()
.outline()
Cube (cuboid)
Generates cuboids.
cube({ corner1: [0, 0, 0],
corner2: [10, 10, 10] })
Cursor
A cursor is moved by transformations rather than the universe around it.
cursor()
.translate(5)
.turn(45)
.translate(5)
.interior()
cursor()
.translate(5)
.turn(-45)
.translate(5)
.interior()
cursor()
.translate(5)
.corner(45)
.translate(5)
.interior()
cursor()
.translate(5)
.corner(-45)
.translate(5)
.interior()
Cylinder
Generates cylinders.
cylinder({ radius: 2,
height: 10,
resolution: 8 })
cylinder({ diameter: 6,
height: 8,
resolution: 16 })
Difference
Difference produces a version of the first shape with the remaining shapes removed, where applicable.
Different kinds of shapes do not interact. e.g., you cannot subtract a surface from a solid.
difference(cube(10).below(),
cube(5).below())
difference(circle(10),
circle(2.5))
difference(assemble(cube().below(),
cube().above()),
cube().right())
Drop from assembly
Generates an assembly from components in an assembly without a tag.
assemble(circle(10).as('A'),
square(10).as('B'))
assemble(circle(10).as('A'),
square(10).as('B'))
.drop('A')
assemble(circle(10).as('A'),
square(10).as('B'))
.drop('B')
assemble(circle(10).as('A'),
square(10).as('B'))
.drop('A', 'B')
Front
Moves the shape so that it is just before the origin.
assemble(cylinder(2, 15).translate([0, 0, 2.5]),
cube(10).front())
Extrude
Generates a solid from a surface.
difference(circle(10),
circle(8))
difference(circle(10),
circle(8))
.extrude({ height: 10 })
Hull
Builds the convex hull of a set of shapes.
hull(point([0, 0, 10]),
circle(10))
assemble(point([0, 0, 10]),
circle(10))
.hull()
point([0, 0, 10]).hull(circle(10))
Interior
Generates a surface from the interior of a simple closed path.
circle(10)
.outline()
.interior()
Intersection
Intersection produces a version of the first shape retaining only the parts included in the remaining shapes.
Different kinds of shapes do not interact. e.g., you cannot intersect a surface and a solid.
intersection(cube(12),
sphere(8))
intersection(circle(10).translate(-5),
circle(10).translate(5))
intersection(assemble(cube().below(),
cube().above()),
sphere(1))
assemble(difference(square(10),
square(7))
.translate(-2, -2),
difference(square(10),
square(7))
.translate(2, 2));
intersection(difference(square(10),
square(7))
.translate(-2, -2),
difference(square(10),
square(7))
.translate(2, 2));
Keep in assembly
Generates an assembly from components in an assembly with a tag.
assemble(circle(10).as('A'),
square(10).as('B'))
assemble(circle(10).as('A'),
square(10).as('B'))
.keep('A')
assemble(circle(10).as('A'),
square(10).as('B'))
.keep('B')
assemble(circle(10).as('A'),
square(10).as('B'))
.keep('A', 'B')
Left
Moves the shape so that it is just to the left of the origin.
assemble(cube(10).left(),
cylinder(2, 15))
Lego
lego.socketSheet().drop('void')
Log
Writes a string to the console.
log("Hello, World")
Max
Produces the maximum of a series of numbers.
max(1, 2, 3, 4) == 4
Measure Bounding Box
Provides the corners of the smallest orthogonal box containing the shape.
const [corner1, corner2] = sphere(7).measureBoundingBox();
cube({ corner1, corner2 })
Micro Gear Motor
Minkowski (convex)
Generates the minkowski sum of a two convex shapes.
minkowski(cube(10),
sphere(3));
Outline
Generates the outline of a surface.
difference(circle(10),
circle(2).translate([-4]),
circle(2).translate([4]))
difference(circle(10),
circle(2).translate([-4]),
circle(2).translate([4]))
.outline()
Point
Generates a point, by default at the origin.
Note: The points are not visible in the illustrations below.
Points
Generates point cloud.
Note: The points are not visible in the illustrations below.
points([ -0.5, -0.5, -0.5 ],
[ -0.5, -0.5, 0.5 ],
[ -0.5, 0.5, -0.5 ],
[ -0.5, 0.5, 0.5 ],
[ 0.5, -0.5, -0.5 ],
[ 0.5, -0.5, 0.5 ],
[ 0.5, 0.5, -0.5 ],
[ 0.5, 0.5, 0.5 ])
hull(points([ -0.5, -0.5, -0.5 ],
[ -0.5, -0.5, 0.5 ],
[ -0.5, 0.5, -0.5 ],
[ -0.5, 0.5, 0.5 ],
[ 0.5, -0.5, -0.5 ],
[ 0.5, -0.5, 0.5 ],
[ 0.5, 0.5, -0.5 ],
[ 0.5, 0.5, 0.5 ]))
Polygon
polygon([0, 1],
[1, 1],
[1, 0],
[0.2, 0.2])
Polyhedron
polyhedron({ points: [[10, 10, 0], [10, -10, 0], [-10, -10, 0], [-10, 10, 0], [0, 0, 10]],
triangles: [[4, 1, 0], [4, 2, 1], [4, 3, 2], [4, 0, 3], [3, 0, 1], [3, 1, 2]] })
Read Data Stitch Tajima
readDst({ path: 'dst/atg-sft003.dst',
sources: [{ file: 'dst/atg-sft003.dst' },
{ url: 'https://jsxcad.js.org/dst/atg-sft003.dst' }] })
readDst({ path: 'dst/atg-sft003.dst',
sources: [{ file: 'dst/atg-sft003.dst' },
{ url: 'https://jsxcad.js.org/dst/atg-sft003.dst' }] })
Read Font
readFont reads in a font and produces a function that renders text as a surface with that font.
The rendering function takes an option defaulting to { emSize = 10 } and a string of text.
This means that one M is 10 mm in height.
const greatVibes = readFont({ path: 'font/great-vibes/GreatVibes-Regular.ttf' });
greatVibes({ emSize: 20 }, "M").extrude(5).rotateX(90).above().center()
const greatVibes = readFont({ path: 'font/great-vibes/GreatVibes-Regular.ttf' });
greatVibes({ emSize: 10 }, "M").center()
const greatVibes = readFont({ path: 'font/great-vibes/GreatVibes-Regular.ttf' });
greatVibes({ emSize: 20 }, "M").center()
const greatVibes = readFont({ path: 'font/great-vibes/GreatVibes-Regular.ttf' });
greatVibes({ emSize: 16 }, "CA").center()
Read LDraw Parts
readLDraw({ part: '3004.dat' })
Read Shape Geometry
This reads tagged geometry in json format and produces a shape.
writeShape({ path: 'geometry/cube' }, cube())
readShape({ path: 'geometry/cube' })
A shape building function can be supplied to generate the shape to read if absent.
The second read will not call the build function, and it will be present in re-runs.
This allows the caching of complex geometry for fast recomposition.
readShape({ path: 'geometry/sphere' }, () => sphere())
readShape({ path: 'geometry/sphere' }, () => sphere())
Read STL
readStl({ path: 'stl/teapot.stl',
format: 'ascii',
sources: [{ file: 'stl/teapot.stl' },
{ url: 'https://jsxcad.js.org/stl/teapot.stl' }] })
Read Scalable Vector Format
const svg = readSvg({ path: 'svg/butterfly.svg',
sources: [{ file: 'svg/butterfly.svg' },
{ url: 'https://jsxcad.js.org/svg/butterfly.svg' }] });
svg.center().scale(0.02)
Right
Moves the shape so that it is just to the right of the origin.
assemble(cube(10).right(),
cylinder(2, 15))
Rotate X
Rotates the shape around the X axis.
Rotate Y
Rotates the shape around the Y axis.
Rotate Z
Rotates the shape around the Z axis.
Scale
Scales an object uniformly or per axis.
Sine
Gives the sine in degrees.
sin(a) => Math.sin(a / 360 * Math.PI * 2);
sin(0) = 0
sin(45) = 0.707
sin(90) = 1
Sphere
Generates spheres.
sphere({ radius: 8, resolution: 5 })
sphere({ diameter: 16, resolution: 64 })
Square Root
Gives the the square root of a number.
sqrt(a) => Math.sqrt(a);
sqrt(0) = 0
sqrt(4) = 2
sqrt(16) = 4
Square (rectangle)
Properly speaking what is produced here are rectangles.
Svg Path
Generates a path from svg path data.
svgPath({},
'M 120.25163,89.678938 C 105.26945,76.865343 86.290871,70.978848 64.320641,70.277872 z')
.center()
.scale(0.2)
Tetrahedron
Generates tetrahedrons.
tetrahedron({ radius: 8 })
tetrahedron({ diameter: 16 })
Translate
Translation moves a shape.
assemble(circle(),
sphere().above())
assemble(circle(),
sphere().above()
.translate(0, 0, 1))
assemble(circle(),
sphere().above()
.translate(0, 1, 0))
assemble(circle(),
sphere().above()
.translate([-1, -1, 1]))
Triangle
triangle({ diameter: 20 })
Union
Union produces a version of the first shape extended to cover the remaining shapes, as applicable.
Different kinds of shapes do not interact. e.g., you cannot union a surface and a solid.
union(sphere(5).left(),
sphere(5),
sphere(5).right())
union(sphere(5).left(),
sphere(5),
sphere(5).right())
.crossSection()
.outline()
union(triangle(),
triangle().rotateZ(180))
union(triangle(),
triangle().rotateZ(180))
.outline()
union(assemble(cube().left(),
cube().right()),
cube().front())
.crossSection()
.outline()
Write PDF
cube().crossSection().writePdf({ path: 'cube.pdf' });
writePdf({ path: 'cube.pdf' }, cube().crossSection());
Write Shape Geometry
This writes a shape as a tagged geometry in json format.
writeShape({ path: 'cube.shape' }, cube())
readShape({ path: 'cube.shape' })
Write STL
cube().writeStl({ path: 'cube.stl' });
readStl({ path: 'cube.stl' });
writeStl({ path: 'cube.stl' }, cube());
readStl({ path: 'cube.stl' });
Write SVG
cube().crossSection().writeSvg({ path: 'svg/cube1.svg' });
readSvg({ path: 'svg/cube1.svg' })
writeSvg({ path: 'svg/cube2.svg' }, cube().crossSection());
readSvg({ path: 'svg/cube2.svg' })
Write SVG Photo
This takes a scene and a camera position and generates a two-dimensional SVG representation
as a svg tag.
cube().writeSvgPhoto({ path: 'svg/cube3.svg', view: { position: [10, 10, 10], target: [0, 0, 0] } });
readSvg({ path: 'svg/cube3.svg' })
writeSvgPhoto({ path: 'svg/cube4.svg', view: { position: [10, 10, 10], target: [0, 0, 0] } }, cube());
readSvg({ path: 'svg/cube4.svg' })